package config

import (
	"context"
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"golang-question/errorx"
)

// Manager 定义了配置管理器的接口
type Manager[T any] interface {
	Get() T
	Update(T) errorx.Error
	OnChange(func(T)) (cancel func())
	Watch() Manager[T]     // 执行Watch后，会开始监听配置的变化，并在变化时自动更新 否则每次Get都会从数据源取得最新资料
	InitData(T) Manager[T] // 如果数据源没有资料，则使用InitData put资料
}

// baseManager 实现了基本的配置管理功能
type baseManager[T any] struct {
	data       T                // 当前配置数据
	mu         sync.RWMutex    // 读写锁，保证并发安全
	callbacks  []func(T)       // 配置变更回调函数列表，当配置发生变化时，会依次调用这些函数
	ctx        context.Context // 用于控制监听协程的生命周期
	cancel     context.CancelFunc // 用于取消监听协程
	isWatching bool            // 标记是否正在监听配置变化
}

// localManager 实现了本地配置管理
type localManager[T any] struct {
	*baseManager[T]
}

// etcdManager 实现了 etcd 配置管理
type etcdManager[T any] struct {
	*baseManager[T]
	// TODO: 添加 etcd 客户端相关字段
}

// Get 获取当前配置
func (m *baseManager[T]) Get() T {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.data
}

// Update 更新配置
func (m *baseManager[T]) Update(data T) errorx.Error {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	// 序列化数据以验证其有效性
	_, err := json.Marshal(data)
	if err != nil {
		return errorx.C(400, fmt.Sprintf("invalid config data: %v", err))
	}

	m.data = data
	m.notifyCallbacks() // 通知所有注册的回调函数
	return nil
}

// OnChange 注册配置变更回调
// 参数 callback 是一个函数，当配置发生变化时会被调用
// 返回值 cancel 是一个函数，调用它可以取消注册的回调
func (m *baseManager[T]) OnChange(callback func(T)) (cancel func()) {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	// 将回调函数添加到列表中
	m.callbacks = append(m.callbacks, callback)
	idx := len(m.callbacks) - 1 // 记录回调函数在列表中的位置

	// 返回取消函数
	return func() {
		m.mu.Lock()
		defer m.mu.Unlock()
		// 通过下标删除回调
		if idx >= 0 && idx < len(m.callbacks) {
			m.callbacks = append(m.callbacks[:idx], m.callbacks[idx+1:]...)
		}
	}
}

// notifyCallbacks 通知所有注册的回调函数
// 当配置发生变化时，会调用此方法通知所有注册的回调函数
func (m *baseManager[T]) notifyCallbacks() {
	for _, callback := range m.callbacks {
		callback(m.data) // 将新的配置数据传递给回调函数
	}
}

// Watch 开始监听配置变化
func (m *baseManager[T]) Watch() Manager[T] {
	if m.isWatching {
		return m
	}
	
	m.isWatching = true
	m.ctx, m.cancel = context.WithCancel(context.Background())
	
	// 启动监听协程
	go func() {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()
		
		lastData, err := json.Marshal(m.Get())
		if err != nil {
			return
		}
		
		for {
			select {
			case <-m.ctx.Done():
				return
			case <-ticker.C:
				currentData, err := json.Marshal(m.Get())
				if err != nil {
					continue
				}
				
				// 如果配置发生变化，通知所有回调
				if string(currentData) != string(lastData) {
					m.notifyCallbacks()
					lastData = currentData
				}
			}
		}
	}()
	
	return m
}

// InitData 初始化配置数据
func (m *baseManager[T]) InitData(data T) Manager[T] {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	m.data = data
	return m
}

// Local 创建一个本地配置管理器
func Local[T any]() Manager[T] {
	return &localManager[T]{
		baseManager: &baseManager[T]{
			callbacks: make([]func(T), 0), // 初始化空的回调函数列表
		},
	}
}

// Etcd 创建一个 etcd 配置管理器
func Etcd[T any]() Manager[T] {
	return &etcdManager[T]{
		baseManager: &baseManager[T]{
			callbacks: make([]func(T), 0), // 初始化空的回调函数列表
		},
	}
}
